package redis.inaction.ratelimiter.filter.metrics;

import io.micrometer.core.instrument.Tags;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import redis.inaction.ratelimiter.support.RouteApiUtils;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;

public class MetricsTagsSupport {

    private static final String TAG_ROUTE_ID = "routeId";
    private static final String TAG_API_CODE = "apiCode";
    private static final String TAG_EXCEPTION = "exception";
    private static final String TAG_HTTP_STATUS_CODE = "httpStatusCode";
    private static final String TAG_OS_TYPE = "osType";

    private static final String UNKNOWN_VALUE = "UNKNOWN";

    public static Tags buildTags(ServerWebExchange exchange, Throwable t) {
        String routeId = getRouteId(exchange);
        String apiCode = RouteApiUtils.getApiCode(exchange, "apiCode");
        return Tags.of(
                TAG_ROUTE_ID, routeId,
                TAG_API_CODE, apiCode,
                TAG_EXCEPTION, t == null ? "none" : t.getClass().getSimpleName(),
                TAG_HTTP_STATUS_CODE, getTagHttpStatusCode(exchange),
                TAG_OS_TYPE, exchange.getAttribute(TAG_OS_TYPE)
        );
    }

    private static String getRouteId(ServerWebExchange exchange) {
        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
        if (route != null) {
            return route.getId();
        }
        return UNKNOWN_VALUE;
    }

    private static String getTagHttpStatusCode(ServerWebExchange exchange) {
        String httpStatusCodeStr = "NA";
        if (exchange.getResponse() instanceof AbstractServerHttpResponse) {
            Integer statusInt = exchange.getResponse().getRawStatusCode();
            if (statusInt != null) {
                httpStatusCodeStr = String.valueOf(statusInt);
            }
        } else {
            HttpStatus statusCode = exchange.getResponse().getStatusCode();
            if (statusCode != null) {
                httpStatusCodeStr = String.valueOf(statusCode.value());
            }
        }

        return httpStatusCodeStr;
    }

}
